﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using ChineseRemainderTheorem.Core;
using ChineseRemainderTheorem.Mvvm;

namespace ChineseRemainderTheorem.ViewModels
{
    public class RestoreViewModel : BaseViewModel
    {
        #region Fields

        #region Services

        private readonly ISecretSharingService _secretSharingService;

        #endregion

        #region Containers for bindable properties

        private BigInteger _secret;

        private int _secretPartsCount;

        private ObservableCollection<SecretPartViewModel> _secretParts;

        private bool _isCalculating;

        private bool _showSecret;

        #endregion

        #region Commands

        private ICommand _restoreCommand;

        private ICommand _clearSecretPartsCommand;
        private int _power;

        #endregion

        #endregion

        #region Properties

        public bool ShowSecret
        {
            get { return _showSecret; }
            set { SetProperty(ref _showSecret, value, "ShowSecret"); }
        }

        public BigInteger Secret
        {
            get { return _secret; }
            set { SetProperty(ref _secret, value, "Secret"); }
        }

        public int SecretPartsCount
        {
            get { return _secretPartsCount; }
            set { SetProperty(ref _secretPartsCount, value, "SecretPartsCount"); }
        }

        public bool IsCalculating
        {
            get { return _isCalculating; }
            set { SetProperty(ref _isCalculating, value, "IsCalculating"); }
        }

        public ObservableCollection<SecretPartViewModel> SecretParts
        {
            get { return _secretParts; }
            set { SetProperty(ref _secretParts, value, "SecretParts"); }
        }

        

        public ICommand RestoreCommand
        {
            get
            {
                return _restoreCommand ?? (_restoreCommand = new SimpleCommand(o => OnRestore(), o => CanRestore()));
            }
        }

        public ICommand ClearSecretPartsCommand
        {
            get
            {
                return _clearSecretPartsCommand ??
                       (_clearSecretPartsCommand =
                           new SimpleCommand(o => OnClearSecretParts(), o => CanClearSecretParts()));
            }
        }

        #endregion

        #region Constructors

        public RestoreViewModel(ISecretSharingService secretSharingService)
        {
            if (ReferenceEquals(secretSharingService, null))
            {
                throw new ArgumentNullException("secretSharingService");
            }
            _secretSharingService = secretSharingService;

            _secretParts = new ObservableCollection<SecretPartViewModel>();
        }

        #endregion

        #region Methods

        private bool CanRestore()
        {
            return SecretPartsCount > 3 && SecretPartsCount < 20 && !ReferenceEquals(SecretParts, null) &&
                   SecretParts.Count > 2 && SecretParts.Count < 19;
        }

        private async void OnRestore()
        {
            IsCalculating = true;
            ShowSecret = false;
            try
            {
                SecretSharingOperation[] secretSharingOperations =
                    SecretParts.Select(s => new SecretSharingOperation(s.Secret, s.Index, s.Mod, s.Power)).ToArray();
                Secret =
                    await
                        _secretSharingService.RestoreAsync(secretSharingOperations, SecretParts.Count, SecretPartsCount);
                ShowSecret = true;
            }
            catch (Exception ex)
            {
                Application.Current.Dispatcher.BeginInvoke(
                    (Func<Window, string, string, MessageBoxButton, MessageBoxResult>) (MessageBox.Show),
                    Application.Current.MainWindow,
                    ex.Message, "Упс, ошибка...", MessageBoxButton.OK);
            }
            finally
            {
                IsCalculating = false;
            }
        }

        private bool CanClearSecretParts()
        {
            return SecretParts.Count != 0;
        }

        private void OnClearSecretParts()
        {
            SecretParts.Clear();
            ShowSecret = false;
        }


        #endregion
    }
}
